Skip to content

Exercises

Window dimensions

Let's use an effect hook to track the window's dimensions over time!

Acceptance Criteria:

  • As the window is resized, the numbers shown in the “Result” tab should update, accurately showing the width and height of the iframe.
  • Only a single event listener should be registered.

Note: You can test this by dragging the division between the two tabs. If you're not using a pointer device, you can focus the divider and use the left/right arrow keys:

Code Playground

import React from 'react';

function WindowSize() {
const [
windowDimensions,
setWindowDimensions,
] = React.useState({
width: window.innerWidth,
height: window.innerHeight,
});
return (
<div className="wrapper">
<p>
{windowDimensions.width} / {windowDimensions.height}
</p>
</div>
);
}

export default WindowSize;

Solution:

Toasty!

In the old Mortal Kombat games, a little fella would occasionally pop out the side of the screen and yell Toasty!, for unclear reasons.

A few years back, I took inspiration from this quirky effect, and used it to slide my 3D mascot out on my blog:

In this exercise, we'll create our own Toasty effect!

It will be tied to scroll position. When the user scrolls to a specific point in the page, a character will slide out from the edge of the screen. We'll use the spiffy IntersectionObserver API to help us out.

There's a lot of stuff in this exercise, and it can seem pretty intimidating. To help you make sense of what's going on, I've prepared a two-minute intro video, to provide some context around how this exercise is meant to work:

Acceptance Criteria:

  • As the user scrolls near the bottom of the page, a ghost character should slide in.
  • This can be accomplished by observing the styles.wrapper element, and setting the isShown state variable to true/false based on whether it's within the viewport or not.
  • You shouldn't use document.querySelector! You can capture a reference to the wrapper element with the React.useRef hook.

Code Playground

import React from 'react';

import styles from './Toasty.module.css';

// Here's how we'd solve this problem using vanilla JS.
// Feel free to repurpose this in your solution!
function pureJsVersion() {
const wrapperElement = document.querySelector('.toasty-wrapper');
const observer = new IntersectionObserver((entries) => {
const [entry] = entries;

if (entry.isIntersecting) {
// Show character
} else {
// Hide character
}
});

observer.observe(wrapperElement);
}

function Toasty() {
// Your goal is to update the `isShown` state variable,
// based on the user's scroll position, using
// IntersectionObserver.
const [isShown, setIsShown] = React.useState(false);
// This CSS value will control whether the ghost is
// visible or not.
const translateX = isShown
? '0%'
: '100%';
return (
<div className={styles.wrapper}>
<div
className={styles.character}
style={{
transform: `translateX(${translateX})`,
}}
>
👻
</div>
</div>
);
}

export default Toasty;

Solution: